#pragma once
#include <list>

namespace bs
{
	class IRunnable;

	class ProcessManager
	{
	public:
		enum ProcessType
		{
			Time,
			Frame
		};

		enum ProcessPriority
		{
			Urgent = 100,
			High = 75,
			Normal = 50,
			Low = 25,
			Lowest = 0
		};

		enum ProcessStatus
		{
			Active,
			Suspended,
			Terminated
		};

		struct ProcessInfo
		{
			int id;
			IRunnable* runner;
			ProcessType type;
			int priority;
			ProcessStatus status;
			size_t begin;
			size_t end;
			size_t period;
			void* userData;
			bool releaseData;
			bool owned;

			size_t next;
			size_t last;
			size_t suspendEnd;
		};

	public:
		static ProcessManager& Instance();

		bool NewProcess(int* id, IRunnable* runner, ProcessType type, int priority, size_t begin, 
			size_t duration, size_t period, void* userData, bool owned = false, bool releaseData = false);

		void Execute(size_t time, size_t frames, size_t elapse);

		void TerminateProcess(int id);
		void TerminateProcess(IRunnable* runner);
		void TerminateAllProcess();

		void SuspendProcess(int id, size_t duration = 0);
		void SuspendAllProcess(size_t duration = 0);

		void ResumeProcess(int id);
		void ResumeAllProcess();

	private:
		ProcessManager();
		~ProcessManager();

		typedef std::list<ProcessInfo*> ProcessInfoList;

		void InsertProcess(ProcessInfo* info);
		void ExecuteProcessList(ProcessInfoList& list, size_t time, size_t frames, size_t elapse);
		void DeleteProcess(ProcessInfo* info);

		ProcessInfo* GetProcess(int id);

	private:
		ProcessInfoList timeProcesses;
		ProcessInfoList frameProcesses;

		int nextId;
	};

}
